Rotha's GearSwap Lessons
This guide is designed to help you create GearSwap files in a step-by-step manner. It'll start with the very basic, and will progress to more advanced techniques as this page gets updated. Although the example codes are designed for Black Mages, the techniques involved will work for all jobs. Before you begin, make sure you have Notepad++ installed on your PC. It makes reading and writing code so much easier than normal notepad. Also, turn on the GearSwap addon in Windower if you have not already. The Basics Now for the fun part. Here we will learn how to layout the script, set equipment, and create basic conditions on when to activate the different functions of the script. The tutorial below will use, as an example, a Black Mage casting the spell "Flare". Layout All GearSwap users files should be stored in C:\Program Files (x86)\Windower4\addons\GearSwap\data\ Any time you log in, or change jobs, GearSwap will look there for file that correspond to your current job. For example, if you change job to Black Mage, it will look for a blm.lua file and automatically load it if one exist. In Notepad++, create a new file, choose a job to name it, and save it as a Lua Source Type. This will make it so the file extension is .lua. For this tutorial, we'll be using Black Mage as our example. So, we'll go ahead and create a blm.lua file and save it in the data folder. Now that we have blm.lua created, open it and enter the following lines: function get_sets() --This function prepares your equipment sets. end ----------------------------------------------------------------------------------- function precast(spell) --This function performs right before the action is sent to the server. end ----------------------------------------------------------------------------------- function midcast(spell) --This function performs after precast but before the action is sent to the server. end ----------------------------------------------------------------------------------- function aftercast(spell) --This function performs after the action has taken place end ----------------------------------------------------------------------------------- Equipment Sets Now lets look at function get_sets(). Below it, you'll write out all of the possible equipment sets you'll be swapping. But for now, let's just work with a couple of equipment pieces. In the function, edit it so that it looks like: function get_sets() sets.precast = {} sets.midcast = {} sets.aftercast = {} end Now lets start filling in equipment. For our example, we'll equip gear as if we're about to cast the spell "Flare" function get_sets() sets.precast = {sub="Vivid Strap +1",feet="Rostrum Pumps"} sets.midcast = {main="Vulcan's Staff",sub="Fire Grip"} sets.aftercast = {main="Terra's Staff",feet="Herald's Gaiters"} end Looking at this, right before the we cast "Flare", precast will equip "Vivid Strap +1" and "Rostrum pumps" for their "Fast Cast" traits. For a mage, precast is mainly used in trying to activate "Fast Cast". For melee, precast is used for preparing beneficial traits for weaponskills. Right before "Flare" activates, midcast then equip gear that will benefit its fire element After Flare is casted, aftercast will equip "Terra's Staff" and "Herald's Gaiters" for their defensive traits. Remember, we've so far only made our equipment sets. The codes won't work until we fill in the rest of the functions. Precast Let's look at function precast(spell). '''This function is called right before your spell/ability/weaponskill is activated. function precast(spell) equip(sets.precast) end By putting in '''equip(sets.precast), '''any time you're about to perform '''any spell/ability/weaponskill, your equipment will be changed based on the sets.precast = {} '''table. If you want to specify conditions on when it should activate, you'll have to use '''if '''statements. We'll go ahead and use them for the next function. ''Midcast & Conditional Statements'' Now it's time for '''function midcast(spell). '''This function comes after precast but before the spell/ability/weaponskill takes place. Since our example is what to equip when casting "Flare", we'll have to make a conditional statement so that it will only activate when "Flare" is casted. function midcast(spell) if spell.english "Flare" then equip(sets.midcast) end end This above example will look at the action you took, and check its English name. It will compare it to the term "Flare". If they match, then it will equip gear based on '''sets.midcast = {}. '''If it does not match, then it will ignore, and not do anything else in the function. ''Aftercast'' And finally, we have '''function aftercast(spell). '''This function is called after performing your spell/ability/weaponskill. You'll want to use this function to go back to your default gear. function aftercast(spell) equip(sets.aftercast) end This will equip your gear based on '''sets.aftercast = {} '''after your actions has taken place. ''Putting it together'' Now that we have a complete set, let's have a look at it as a whole. function get_sets() sets.precast = {sub="Vivid Strap +1",feet="Rostrum Pumps"} sets.midcast = {main="Vulcan's Staff",sub="Fire Grip"} sets.aftercast = {main="Terra's Staff",feet="Herald's Gaiters"} end ----------------------------------------------------------------------------------- function precast(spell) equip(sets.precast) end ----------------------------------------------------------------------------------- function midcast(spell) if spell.english "Flare" then equip(sets.midcast) end end ----------------------------------------------------------------------------------- function aftercast(spell) equip(sets.aftercast) end ----------------------------------------------------------------------------------- Go ahead and try it! You'll see that it work. However, there's one small problem. You'll definitely want more than just a "Flare" script. You have hundreds of other spells and abilities! So, instead of occupying the main tables (sets.precast, sets.midcast, sets.aftercast), you'll want to make your own. We call these '''sub-tables. Sub-tables function get_sets() sets.precast = {} sets.precast.fc = {sub="Vivid Strap +1",feet="Rostrum Pumps"} sets.midcast = {} sets.midcast.flare = {main="Vulcan's Staff",sub="Fire Grip"} sets.midcast.quake = {main="Terra's Staff",sub="Earth Grip"} sets.aftercast = {main="Terra's Staff",feet="Herald's Gaiters"} end ----------------------------------------------------------------------------------- function precast(spell) if spell.type:contains('Magic') then ' equip(sets.precast.fc)' end end ----------------------------------------------------------------------------------- function midcast(spell) if spell.english "Flare" then equip(sets.midcast.flare) end if spell.english "Quake" then equip(sets.midcast.quake) end end ----------------------------------------------------------------------------------- function aftercast(spell) equip(sets.aftercast) end ----------------------------------------------------------------------------------- Above in bold are the changes made to accommodate future actions and equipment swaps. sets.precast = {} 'and '''sets.midcast = {} '''were left blank so that those main tables exist. Without them, their sub-tables will not work at all. '''sets.precast.fc '''is a sub-table that was made for "Fast Cast". You could've named it sets.precast.'anything. '''fc was easy enough to remember for "Fast Cast". If you decide to name it something else, just remember to call it correctly in your precast function. '''sets.midcast.flare was created specifically for the spell "Flare". You can add more spells by creating more subtables with unique names below it and creating their respective equipment sets. (example sets.midcast.quake) In function precast(spell), 'you'll notice a new condition. What is happening here is the function is looking at your action, and checking its type. It'll find either '''JobAbility, Weaponskill, WhiteMagic, BlackMagic, BardSong, '''or something else. It will compare what it finds with the term "'Magic". If the type it finds contains '''"Magic" whether its BlackMagic or WhiteMagic, it will return as true and work the rest of the command '''equip(sets.precast.fc). '''If the type it finds does not contain the term "Magic", then it will ignore and no action will take place in this function. In '''function midcast(spell), '''when conditions are met, it will now call upon either '''sets.midcast.flare or sets.midcast.quake and equip the appropriate gear. The Basics Concluded So far, we've learned how to create the basic layout of a GearSwap file, make equipment sets, and formulate conditions on when gear swapping should take place. With this basic understanding, you can create rudimentary gearswap files for any spell, or ability. 'Intermediate' The basics are fine for creating equipment sets, but it lacks the control you sometimes need for more complex situations. In this tutorial, we'll practice with more conditional statements and learn more about the different functions and variables available in GearSwap. ''Post Aftercast and More Conditional Statements When we last left off, '''aftercast '''didn't really do much. It simply equip gear assigned to it after each and every spell or ability. But not every post-action situation calls for the same equipment. Let's alter our last example a bit: function get_sets() sets.precast = {} sets.precast.fc = {sub="Vivid Strap +1",feet="Rostrum Pumps"} sets.midcast = {} sets.midcast.flare = {main="Vulcan's Staff",sub="Fire Grip"} sets.midcast.quake = {main="Terra's Staff",sub="Earth Grip"} ' sets.aftercast = {}' ' sets.aftercast.idle = {main="Terra's Staff", feet="Herald's Gaiters"}' ' sets.aftercast.rest = {main="Chatoyant Staff"}' ' sets.aftercast.engaged = {waist="Life Belt"}' end ----------------------------------------------------------------------------------- function precast(spell) if spell.type:contains('Magic') then equip(sets.precast.fc) end end ----------------------------------------------------------------------------------- function midcast(spell) if spell.english "Flare" then equip(sets.midcast.flare) end if spell.english "Quake" then equip(sets.midcast.quake) end end ----------------------------------------------------------------------------------- function aftercast(spell) ' if player.status "Engaged" then''' equip(sets.aftercast.engaged) elseif player.status "Idle" then equip(sets.aftercast.idle) end end ----------------------------------------------------------------------------------- function status_change(new,old) ' if new 'Idle' then' equip(sets.aftercast.idle) elseif new 'Resting' then equip(sets.aftercast.rest) elseif new 'Engaged' then equip(sets.aftercast.engaged) end end ----------------------------------------------------------------------------------- In bold are the new changes. As you can see, we did quite a lot. We made an empty sets.aftercast 'table so that it exists for the sub-tables ''sets.aftercast.idle,'' ''sets.aftercast.rest, and '''sets.aftercast.engaged. In function aftercast(spell) we called upon a the variable player.status and see if the player was engaged with a mob or not. If it is, then it will call sets.aftercast.engaged and equip melee suitable gear. Below that is a new function called status_change(new,old). '''This function is called every time a player's status changes (Engaged, Idle, Resting, Dead). It will pass on the new status to the variable '''new '''and old status to the variable '''old. In the example, the status_change function checks the new status and sees if you're idle, resting, or engaged, and it will equip the appropriate gear set. The reason why we use this function', '''is so your gear changes '''any time' your status change. aftercast '''will only check those conditions after performing a spell or ability. Functions So far, we've already encounterd a handful of functions: get.sets, precast, midcast, aftercast, and most recently status_change. However, there are a few more that needs to be addressed. There are many more built-in functions, but we'll only look at these for now. Similar to the normal midcast and aftercast functions, '''pet_midcast, and pet_aftercast '''will activate when your pet performs an action. '''buff_change is a neat function. The name of the buff/debuff is passed onto the variable name, '''while the '''gain '''variable will be passed the values of '''True '''or '''False. True if the buff was added to your buff status bar, or False if the buff was removed from your status bar. Let's create an example and then analyze it. function get_sets() sets.buff = {} sets.buff.sleep {neck = "Opo-opo Necklace"} end ----------------------------------------------------------------------------------- function buff_change(name,gain) if name "sleep" and gain "True" then equip(sets.buff.sleep) end end ----------------------------------------------------------------------------------- Here we created a table called sets.buff and the sub-table sets.buff.sleep. Below that we set the buff_change function to check on whether or not your character have been put to sleep. If you have been put to sleep, then the function will equip the "Opo-opo Necklace" to gain TP while you sleep. send_command is also useful. It allows you to send commands directly to Windower's console. You must prefix a console command with @'''. Lets look at another example. function buff_change(name,gain) if name "silence" and gain "True" then send_command('@input /item "Echo Drops" ') end end Here we have a standalone function that checks on whether or not your character is silenced. If true, '''send_command will issue a command to Windower's console, in this instance the input command. input is a windower command that sends text to the game server. In our example, input sends the text command to use "Echo Drops" on yourself. ''Spell Variables Earlier in The Basics, you learned about the '''spell.english' and spell.type variables. These are just a few of the many variables you'll encounter to make more flexible scripts. Below are a few more. In the table above, you'll notice that information about these variables can be "Obtained from resources." The resource it refers to can be found in C:\Program Files (x86)\Windower4\res\. '''Use these file as a guide to help you. (Note that these files are based on FFXI's retail data. Information such as mp cost may or may not match SuperNova's classic data) In our example in '''The Basics '''we use a couple of ways to read data coming from these variables. The direct comparison route uses math operators to check whether the data is true or not ( , >, >=, <, <=) example: 'spell.skill 'Ability' '(This checks if the user action was an "Ability", and sends a True or False statement. The search routes looks for data within the variable and sends a True or False based on what it finds.You can achieve this method by appending the variable with ''':startswith('data'), :contains('data'), '''or :endswith('data'). example: 'spell.skill:startswith('Healing') '(This checks if the user action is an ability that depends on a skill starting with the term "Healing", and sends a True or False statement) Let's create an example script function aftercast(spell) if spell.english:startswith('Thunder') and spell.interrupted then if spell.english:endswith('IV') then send_command('@input /ma "Thunder III" ') elseif spell.english:endswith('III') then send_command('@input /ma "Thunder II" ') elseif spell.english:endswith('II') then send_command('@input /ma "Thunder" ') end end end Now we must decipher this nested condition statement. This function attempts to cast a Thunder spell, and if it fails to do so, will pick the next lower tier. Assuming the user failed to cast "Thunder IV", the script will then attempt to cast "Thunder III". If it can do so, then this function will no longer act. If however, that also fails, the scrip will then attempt to cast "Thunder II", and "Thunder" if need be. (This is not the ideal way of achieving this task. However, it's the best we have with what we've learned so far). ''Player Variables'' In addition to the data from spells and abilities, you can also collect data from yourself or your pet. The main variables are '''player and pet. By attaching them to one of the keys below, you can gather any information about yourself or your pet. example: player.max_hp And here is the example script function get_sets() sets.midcast = {} sets.midcast.ring = {ring1="Sorcerer's Ring"} end ----------------------------------------------------------------------------------- function midcast(spell) if spell.skill "Elemental Magic" and player.hpp < 76 and player.tp < 100 then equip(sets.midcast.ring) end end ----------------------------------------------------------------------------------- In this example, we've set a condition that would equip the "Sorcerer's Ring" if the user action has the skill type of "Elemental Magic" and if the player HP is less than 76% and if the player's TP is less than 100% (eq to 1000 tp). Only when these conditions are met will equip(sets.midcast.ring) be called. ''Putting it together Below is an example of everything learned so far. This time, the equipment list is complete and formated for readibility function get_sets() sets.precast = {} sets.precast.fc = {sub="Vivid Strap +1",feet="Rostrum Pumps"} ----------------------- sets.midcast = {} sets.midcast.ring = {ring1="Sorcerer's Ring"} sets.midcast.flare = {main="Vulcan's Staff",sub="Fire Grip",ammo="Hedgehog Bomb", head="Demon Helm +1",neck="Caract Choker",ear1="Moldavite Earring",ear2="Crapaud Earring", body="Genie Weskit",hands="Genie Manillas",ring1="Snow Ring",ring2="Snow Ring", back="Hecate's Cape",waist="Witch Sash",legs="Mahatma Slops",feet="Mahant Sandals"} sets.midcast.quake = {main="Terra's Staff",sub="Earth Grip",ammo="Hedgehog Bomb", head="Demon Helm +1",neck="Caract Choker",ear1="Moldavite Earring",ear2="Crapaud Earring", body="Genie Weskit",hands="Genie Manillas",ring1="Snow Ring",ring2="Snow Ring", back="Hecate's Cape",waist="Witch Sash",legs="Mahatma Slops",feet="Mahant Sandals"} ----------------------- sets.aftercast = {} sets.aftercast.engaged = {} sets.aftercast.idle = {main="Terra's Staff", head="Walahra Turban", body="Dalmatica +1", waist="Headlong Belt", feet="Herald's Gaiters"} sets.aftercast.rest = {main="Chatoyant Staff",sub="Staff Strap",ammo="Hedgehog Bomb", head="Cobra Hat",neck="Beak Necklace +1",ear1="Rapture Earring",ear2="Antivenom Earring", body="Mahatma Hpl.",hands="Genie Gages",ring1="Celestial Ring",ring2="Celestial Ring", back="Invigorating Cape",waist="Hierarch Belt",legs="Mahatma Slops",feet="Arborist Nails"} end ----------------------------------------------------------------------------------- function precast(spell) if spell.type:contains('Magic') then equip(sets.precast.fc) end end ----------------------------------------------------------------------------------- function midcast(spell) if spell.english "Flare" then equip(sets.midcast.flare) end if spell.english "Quake" then equip(sets.midcast.quake) end if spell.skill "Elemental Magic" and player.hpp < 76 and player.tp < 100 then equip(sets.midcast.ring) end end ----------------------------------------------------------------------------------- function aftercast(spell) if player.status "Engaged" then equip(sets.aftercast.engaged) elseif player.status "Idle" then equip(sets.aftercast.idle) end end ----------------------------------------------------------------------------------- function status_change(new,old) if new 'Idle' then equip(sets.aftercast.idle) elseif new 'Resting' then equip(sets.aftercast.rest) end end ----------------------------------------------------------------------------------- function buff_change(name,gain) if name "silence" and gain "True" then send_command('@input /item "Echo Drops" ') end end ----------------------------------------------------------------------------------- In the midcast(spell) function above, you'll notice that I have the sets.midcast.ring condition come last. This is due to the fact that condition statements are done in order. And with it being last, there's no chance for other equip sets to override the ring's slot placement. You'll also notice that it's getting pretty crowded in the get_sets() function. And this is with only two spells listed! For the sake of not having to edit for each and every spell, ability, and weaponskill, we'll have to shrink it down as much as possible, without having to sacrifice any gear. Shrink it! As with any good code, the smaller the better. This allows for faster edits in the long run. Plus, it looks nicer. The following may have more or less lines that the previous code. However, this version is consice enough to parse all elemental nukes, instead of just the two "Flare" and "Quake" spells. function get_sets() sets.precast = {} sets.precast.fc = {sub="Vivid Strap +1",feet="Rostrum Pumps"} ----------------------- sets.midcast = {} sets.midcast.ring = {ring1="Sorcerer's Ring"} sets.midcast.earth = {main="Terra's Staff",sub="Earth Grip"} sets.midcast.water = {main="Neptune's Staff",sub="Water Grip"} sets.midcast.wind = {main="Auster's Staff",sub="Wind Grip"} sets.midcast.fire = {main="Vulcan's Staff",sub="Fire Grip"} sets.midcast.ice = {main="Aquilo's Staff",sub="Ice Grip"} sets.midcast.thunder = {main="Jupiter's Staff",sub="Thunder Grip"} sets.midcast.dark = {main="Pluto's Staff",sub="Dark Grip"} sets.midcast.light = {main="Chatoyant's Staff",sub="Light Grip"} sets.midcast.nuke ={ammo="Hedgehog Bomb", head="Demon Helm +1",neck="Caract Choker",ear1="Moldavite Earring",ear2="Crapaud Earring", body="Genie Weskit",hands="Genie Manillas",ring1="Snow Ring",ring2="Snow Ring", back="Hecate's Cape",waist="Witch Sash",legs="Mahatma Slops",feet="Mahant Sandals"} ----------------------- sets.aftercast = {} sets.aftercast.engaged = {} sets.aftercast.idle = {main="Terra's Staff", head="Walahra Turban", body="Dalmatica +1", waist="Headlong Belt", feet="Herald's Gaiters"} sets.aftercast.rest = {main="Chatoyant Staff",sub="Staff Strap",ammo="Hedgehog Bomb", head="Cobra Hat",neck="Beak Necklace +1",ear1="Rapture Earring",ear2="Antivenom Earring", body="Mahatma Hpl.",hands="Genie Gages",ring1="Celestial Ring",ring2="Celestial Ring", back="Invigorating Cape",waist="Hierarch Belt",legs="Mahatma Slops",feet="Arborist Nails"} end ----------------------------------------------------------------------------------- function precast(spell) if spell.type:contains('Magic') then equip(sets.precast.fc) end end ----------------------------------------------------------------------------------- function midcast(spell) if spell.element "Earth" then equip(sets.midcast.earth) elseif spell.element "Water" then equip(sets.midcast.water) elseif spell.element "Wind" then equip(sets.midcast.wind) elseif spell.element "Fire" then equip(sets.midcast.fire) elseif spell.element "Ice" then equip(sets.midcast.ice) elseif spell.element "Thunder" then equip(sets.midcast.thunder) elseif spell.element "Dark" then equip(sets.midcast.dark) elseif spell.element "Light" then equip(sets.midcast.light) end if spell.skill "Elemental Magic" then equip(sets.midcast.nuke) if player.hpp < 76 and player.tp < 100 then equip(sets.midcast.ring) end end end ----------------------------------------------------------------------------------- function aftercast(spell) if player.status "Engaged" then equip(sets.aftercast.engaged) elseif player.status "Idle" then equip(sets.aftercast.idle) end end ----------------------------------------------------------------------------------- function status_change(new,old) if new 'Idle' then equip(sets.aftercast.idle) elseif new 'Resting' then equip(sets.aftercast.rest) elseif new 'Engaged' then equip(sets.aftercast.engaged) end end ----------------------------------------------------------------------------------- function buff_change(name,gain) if name "silence" and gain "True" then send_command('@input /item "Echo Drops" ') end end ----------------------------------------------------------------------------------- As you can see, I took out the common equipment from the "Flare" and "Quake" (which were mostly MAB, and INT gear) and place them in their own set called '''set.midcast.nuke'. I then made an equip set for each element type. As for the midcast function, I created a condition nest checking for the element type and equipping the correct elemental staff and grip. Then it checks the action's skill type and equip the nuke gear if it was "Elemental Magic". Further into that same condition scipt, it checks for player's MP and TP in case it needed to equip "Sorcerer's Ring." ''Intermediate Concluded In this lesson, you've learned about nested conditions, functions, and built in variables. Also you have some resource files you can look up to better aid your script making. I will include more the locations again in the postscript. Hopefully, you've learned enough here to teach yourself new tricks and shortcuts for building better scripts. Next up, is Advanced Mode! Resources GearSwap Global Variables GearSwap Functions Windower Commands FFXI resource data files: '''C:\Program Files (x86)\Windower4\res\'